home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 / Ham Radio 2000.iso / ham2000 / tcp_ip / os2 / pmnos11s / nr4.c < prev    next >
Text File  |  1993-07-30  |  24KB  |  841 lines

  1. /* net/rom level 4 (transport) protocol implementation
  2.  * Copyright 1989 by Daniel M. Frank, W9NK.  Permission granted for
  3.  * non-commercial distribution only.
  4.  * Ported to NOS by SM0RGV, 890525.
  5.  * Inactivity timeout by WG7J, 920325
  6.  */
  7.  
  8. #include <stdio.h>
  9. #include "global.h"
  10. #include "config.h"
  11. #include "mbuf.h"
  12. #include "timer.h"
  13. #include "ax25.h"
  14. #include "lapb.h"
  15. #include "netrom.h"
  16. #include "nr4.h"
  17. #include <ctype.h>
  18.  
  19. #undef NR4DEBUG
  20.  
  21. /* Globals: */
  22.  
  23. /* The circuit table */
  24.  
  25. struct nr4circp Nr4circuits[NR4MAXCIRC];
  26.  
  27. /* Various limits */
  28.  
  29. unsigned short Nr4window = 4;        /* Max window to negotiate */
  30. unsigned short Nr4retries = 10;    /* Max retries */
  31. unsigned short Nr4qlimit = 2048;    /* Max bytes on receive queue */
  32.  
  33. /* Timers */
  34.  
  35. int32 Nr4irtt = 15000;            /* Initial round trip time */
  36. int32 Nr4acktime = 3000;        /* ACK delay timer */
  37. int32 Nr4choketime = 180000;    /* CHOKEd state timeout */
  38.  
  39. static void nr4ackours __ARGS((struct nr4cb *, unsigned, int));
  40. static void nr4choke __ARGS((struct nr4cb *));
  41. static void nr4gotnak __ARGS((struct nr4cb *, unsigned));
  42. static void nr4rframe __ARGS((struct nr4cb *, unsigned, struct mbuf *));
  43.  
  44. #ifdef NR4TDISC
  45.  
  46. int32 Nr4tdiscinit = 0;          /* Inactivity timeout - WG7J */
  47.  
  48. int
  49. donr4tdisc(argc,argv,p)
  50. int argc;
  51. char *argv[];
  52. void *p;
  53. {
  54.     return setlong(&Nr4tdiscinit,"NR4 redundancy timer (sec)",argc,argv);
  55. }
  56.  
  57. /* Changes are if we reachs this, with 'normal' values of tdisc,
  58.  * the other end has already timed  and retried out.
  59.  * So simply reset the control block - WG7J
  60.  */
  61.  
  62. #ifdef notdef
  63. /* This doesn't seem to catch ALL cases,
  64.  * if someone can fix this, please let me know - WG7J
  65.  */
  66. void
  67. nr4_redundant(cb)
  68. struct nr4cb *cb;
  69. {
  70.     struct nr4hdr hdr;
  71.  
  72.     switch(cb->state){
  73.     case NR4STCPEND:
  74.     case NR4STCON:
  75.         /* Format disconnect request packet */
  76.         hdr.opcode = NR4OPDISRQ ;
  77.         hdr.yourindex = cb->yournum ;
  78.         hdr.yourid = cb->yourid ;
  79.  
  80.         /* Set and start timer */
  81.         cb->cdtries = 1 ;
  82.         set_timer(&cb->tcd,2 * cb->srtt);
  83.         cb->tcd.func = nr4cdtimeout ;
  84.         cb->tcd.arg = cb ;
  85.         start_timer(&cb->tcd) ;
  86.  
  87.         /* Send packet */
  88.         nr4sframe(cb->remote.node, &hdr, NULLBUF) ;
  89.  
  90.         /* Signal state change.  nr4state will take care of stopping */
  91.         /* the appropriate timers and resetting window pointers. */
  92.         nr4state(cb, NR4STDPEND) ;
  93.         break;
  94.     }
  95.  
  96. }
  97. #endif
  98.  
  99. #endif /* NR4TDISC */
  100.  
  101.  
  102.  
  103. /* This function is called when a net/rom layer four frame */
  104. /* is discovered inside a datagram addressed to us */
  105.  
  106. void
  107. nr4input(hdr,bp)
  108. struct nr4hdr *hdr;
  109. struct mbuf *bp;
  110. {
  111.     struct nr4hdr rhdr;
  112.     struct nr4cb *cb, *cb2;
  113.     int op;
  114.     unsigned window;
  115.     int acceptc;        /* indicates that connection should be accepted */
  116.     int newconn;        /* indicates that this is a new incoming */
  117.                         /* connection.  You'll see. */
  118.     int gotchoke;        /* The choke flag was set in this packet */
  119.     int i;
  120.     long t;
  121.     
  122.     op = hdr->opcode & NR4OPCODE;    /* Mask off flags */
  123.     
  124.     if(op == NR4OPCONRQ){            /* process connect request first */
  125.         acceptc = 1;
  126.         newconn = 0;
  127.  
  128.         /* These fields are sent regardless of success */
  129.         rhdr.yourindex = hdr->u.conreq.myindex;
  130.         rhdr.yourid = hdr->u.conreq.myid;
  131.  
  132.         /* Check to see if we have already received a connect */
  133.         /* request for this circuit. */
  134.         if((cb = match_n4circ(hdr->u.conreq.myindex,
  135.          hdr->u.conreq.myid,hdr->u.conreq.user,hdr->u.conreq.node))
  136.          == NULLNR4CB){    /* No existing circuit if NULL */
  137.             
  138.             /* If low on memory, don't accept - WG7J */
  139.             if(availmem() < Memthresh)
  140.                 acceptc = 0;
  141.             else {
  142.                 /* Try to get a new circuit */
  143.                 if((cb = new_n4circ()) == NULLNR4CB)
  144.                     acceptc = 0;
  145.                 /* See if we have any listening sockets */
  146.                 for(i = 0; i < NR4MAXCIRC; i++){
  147.                     if((cb2 = Nr4circuits[i].ccb) == NULLNR4CB)
  148.                         continue;/* not an open circuit */
  149.                     if(cb2->state == NR4STLISTEN)
  150.                         /* A listener was found */
  151.                         break;
  152.                 }
  153.                 if(i == NR4MAXCIRC){ /* We are refusing connects */
  154.                     acceptc = 0;
  155.                     free_n4circ(cb);
  156.                 }
  157.                 if(acceptc){
  158.                     /* Load the listeners settings */
  159.                     cb->clone = cb2->clone;
  160.                     cb->user = cb2->user;
  161.                     cb->t_upcall = cb2->t_upcall;
  162.                     cb->s_upcall = cb2->s_upcall;
  163.                     cb->r_upcall = cb2->r_upcall;
  164.                     ASSIGN(cb->local,cb2->local);
  165.  
  166.                     /* Window is set to min of the offered
  167.                      * and local windows
  168.                      */
  169.                     window = hdr->u.conreq.window > Nr4window ?
  170.                             Nr4window : hdr->u.conreq.window;
  171.  
  172.                     if(init_nr4window(cb, window) == -1){
  173.                         free_n4circ(cb);
  174.                         acceptc = 0;
  175.                     } else {
  176.                         /* Set up control block */
  177.                         cb->yournum = hdr->u.conreq.myindex;
  178.                         cb->yourid = hdr->u.conreq.myid;
  179.                         memcpy(cb->remote.user,
  180.                             hdr->u.conreq.user,AXALEN);
  181.                         memcpy(cb->remote.node,
  182.                             hdr->u.conreq.node,AXALEN);
  183.                         /* Default round trip time */
  184.                         cb->srtt = Nr4irtt;
  185.                         /* set up timers, window pointers */
  186.                         nr4defaults(cb);
  187.                         cb->state = NR4STDISC;
  188.                         newconn = 1;
  189.                     } /* End if window successfully allocated */
  190.                 }   /* End if new circuit available */
  191.             } /* End of memory-low else */
  192.          } /* End if no existing circuit matching parameters */
  193.  
  194.         /* Now set up response */
  195.         if(!acceptc){
  196.             rhdr.opcode = NR4OPCONAK | NR4CHOKE;/* choke means reject */
  197.             rhdr.u.conack.myindex = 0;
  198.             rhdr.u.conack.myid = 0;
  199.             rhdr.u.conack.window = 0;
  200.         } else {
  201.             rhdr.opcode = NR4OPCONAK;
  202.             rhdr.u.conack.myindex = cb->mynum;
  203.             rhdr.u.conack.myid = cb->myid;
  204.             rhdr.u.conack.window = cb->window;
  205.         }
  206.         nr4sframe(hdr->u.conreq.node, &rhdr, NULLBUF);
  207.  
  208.         /* Why, you ask, do we wait until now for the state change
  209.          * upcall?  Well, it's like this:  if the state change triggers
  210.          * something like the mailbox to send its banner, the banner
  211.          * would have gone out *before* the conn ack if we'd done this
  212.          * in the code above.  This is what happens when you don't plan
  213.          * too well.  Learn from my mistakes :-)
  214.          */
  215.         if(newconn)
  216.             nr4state(cb, NR4STCON);/* connected (no 3-way handshake) */
  217.             
  218.         free_p(bp);
  219.         return;
  220.     } /* end connect request code */
  221.  
  222.     /* validate circuit number */
  223.     if((cb = get_n4circ(hdr->yourindex, hdr->yourid)) == NULLNR4CB){
  224.         free_p(bp);
  225.         return;
  226.     }
  227.  
  228.     /* Check for choke flag */
  229.     if(hdr->opcode & NR4CHOKE)
  230.         gotchoke = 1;
  231.     else
  232.         gotchoke = 0;
  233.     
  234.     /* Here's where the interesting stuff gets done */
  235.     switch(cb->state){
  236.     case NR4STCPEND:
  237.         switch(op){
  238.         case NR4OPCONAK:
  239.             /* Save the round trip time for later use */
  240.             t = dur_timer(&cb->tcd) - read_timer(&cb->tcd);
  241.             stop_timer(&cb->tcd);
  242.             if(gotchoke){        /* connect rejected */
  243.                 cb->dreason = NR4RREFUSED;
  244.                 nr4state(cb, NR4STDISC);
  245.                 break;
  246.             }
  247.             cb->yournum = hdr->u.conack.myindex;
  248.             cb->yourid = hdr->u.conack.myid;
  249.             window = hdr->u.conack.window > Nr4window ?
  250.                      Nr4window : hdr->u.conack.window;
  251.  
  252.             if(init_nr4window(cb, window) == -1){
  253.                 cb->dreason = NR4RRESET;
  254.                 nr4state(cb, NR4STDISC);
  255.             } else {
  256.                 nr4defaults(cb);    /* set up timers, window pointers */
  257.                 
  258.                 if(cb->cdtries == 1)    /* No retries */
  259.                     /* Use measured rtt */
  260.                     cb->srtt = t;
  261.                 else
  262.                     /* else use default */
  263.                     cb->srtt = Nr4irtt;
  264.                     
  265.                 nr4state(cb, NR4STCON);
  266.                 nr4output(cb);        /* start sending anything on the txq */
  267.             }
  268.             break;
  269.         default:
  270.             /* We can't respond to anything else without
  271.              * Their ID and index
  272.              */
  273.               free_p(bp);
  274.             return;
  275.         }
  276.         break;
  277.     case NR4STCON:
  278.         switch(op){
  279.         case NR4OPDISRQ:
  280.             /* format reply packet */
  281.             rhdr.opcode = NR4OPDISAK;
  282.             rhdr.yourindex = cb->yournum;
  283.             rhdr.yourid = cb->yourid;
  284.             nr4sframe(cb->remote.node,&rhdr,NULLBUF);
  285.             cb->dreason = NR4RREMOTE;
  286.             nr4state(cb, NR4STDISC);
  287.             break;
  288.           case NR4OPINFO:
  289.             /* Do receive frame processing */
  290.               nr4rframe(cb, hdr->u.info.txseq, bp);
  291.  
  292.             /* Reset the choke flag if no longer choked.  Processing
  293.              * the ACK will kick things off again.
  294.              */
  295.             if(cb->choked && !gotchoke){
  296.                 stop_timer(&cb->tchoke);
  297.                 cb->choked = 0;
  298.             }
  299.                 
  300.             /* We delay processing the receive sequence number until
  301.              * now, because the ACK might pull more off the txq and send
  302.              * it, and we want the implied ACK in those frames to be right
  303.              *
  304.              * Only process NAKs if the choke flag is off.  It appears
  305.              * that NAKs should never be sent with choke on, by the way,
  306.              * but you never know, considering that there is no official
  307.              * standard for this protocol
  308.              */
  309.             if(hdr->opcode & NR4NAK && !gotchoke)
  310.                 nr4gotnak(cb, hdr->u.info.rxseq);
  311.  
  312.             /* We always do ACK processing, too, since the NAK of one
  313.              * packet may be the implied ACK of another.  The gotchoke
  314.              * flag is used to prevent sending any new frames, since
  315.              * we are just going to purge them next anyway if this is
  316.              * the first time we've seen the choke flag.  If we are
  317.              * already choked, this call will return immediately.
  318.              */
  319.             nr4ackours(cb, hdr->u.info.rxseq, gotchoke);
  320.  
  321.             /* If we haven't seen the choke flag before, purge the
  322.              * send window and set the timer and the flag.
  323.              */
  324.             if(!cb->choked && gotchoke)
  325.                 nr4choke(cb);
  326.             break;
  327.           case NR4OPACK:
  328.             if(cb->choked && !gotchoke){
  329.                 /* clear choke if appropriate */
  330.                 stop_timer(&cb->tchoke);
  331.                 cb->choked = 0;
  332.             }    
  333.               if(hdr->opcode & NR4NAK && !gotchoke)
  334.                 nr4gotnak(cb, hdr->u.ack.rxseq);    /* process NAKs */
  335.                 
  336.               nr4ackours(cb, hdr->u.ack.rxseq, gotchoke); /* and ACKs */
  337.  
  338.             if(!cb->choked && gotchoke)    /* First choke seen */
  339.                 nr4choke(cb);        /* Set choke status */
  340.  
  341.             break;
  342.         }
  343.         break;
  344.     case NR4STDPEND:
  345.         switch(op){
  346.         case NR4OPDISAK:
  347.               cb->dreason = NR4RNORMAL;
  348.             nr4state(cb, NR4STDISC);
  349.             break;
  350.         case NR4OPINFO:
  351.             /* We can still do receive frame processing until
  352.              * the disconnect acknowledge arrives, but we won't
  353.              * bother to process ACKs, since we've flushed our
  354.              * transmit buffers and queue already.
  355.              */
  356.               nr4rframe(cb, hdr->u.info.txseq, bp);
  357.             break;
  358.         }
  359.     }    /* End switch(state) */
  360. }
  361.  
  362.  
  363. /* Send a net/rom layer 4 frame.  bp should be NULLBUF unless the frame
  364.  * type is info.
  365.  */
  366. void
  367. nr4sframe(dest, hdr, bp)
  368. char *dest;
  369. struct nr4hdr *hdr;
  370. struct mbuf *bp;
  371. {
  372.     struct mbuf *n4b;
  373.  
  374.     if((n4b = htonnr4(hdr)) == NULLBUF){
  375.         free_p(bp);
  376.         return;
  377.     } else {
  378.         append(&n4b, bp);
  379.         nr3output(dest, n4b);
  380.     }
  381. }
  382.  
  383. /* Receive frame processing */
  384. static void
  385. nr4rframe(cb, rxseq, bp)
  386. struct nr4cb *cb;
  387. unsigned rxseq;
  388. struct mbuf *bp;
  389. {
  390.     struct nr4hdr rhdr;
  391.     unsigned window = cb->window;
  392.     unsigned rxbuf = rxseq % window;
  393.     unsigned newdata = 0;        /* whether to upcall */
  394.  
  395. #ifdef NR4DEBUG
  396.     tprintf("Processing received info\n");
  397. #endif
  398.  
  399. #ifdef NR4TDISC
  400.     /* We received data, reset the inactivity timer - WG7J */
  401.     start_timer(&cb->tdisc);
  402. #endif
  403.  
  404.     /* If we're choked, just reset the ACK timer to blast out
  405.      * another CHOKE indication after the ackdelay
  406.      */
  407.     if(cb->qfull){
  408.         start_timer(&cb->tack);
  409.         return;
  410.     }
  411.     
  412.     /* If frame is out of sequence, it is either due to a lost frame
  413.      * or a retransmission of one seen earlier.  We do not want to NAK
  414.      * the latter, as the far end would see this as a requirement to
  415.      * retransmit the expected frame, which is probably already in the
  416.      * pipeline.  This in turn would cause another out-of-sequence
  417.      * condition, another NAK, and the process would repeat indefinitely.
  418.      * Therefore, if the frame is out-of-sequence, but within the last
  419.      * 'n' frames by sequence number ('n' being the window size), just
  420.      * accept it and discard it.  Else, NAK it if we haven't already.
  421.      *    (Modified by Rob Stampfli, kd8wk, 9 Jan 1990)
  422.      */
  423.     if(rxseq != cb->rxpected && !cb->naksent){
  424. #ifdef NR4DEBUG
  425.         tprintf("Frame out of sequence -- expected %u, got %u.\n",
  426.                cb->rxpected, rxseq);
  427. #endif                
  428.         if(nr4between(cb->rxpected,
  429.            (rxseq + window) & NR4SEQMASK, cb->rxpastwin))
  430.             /* just a repeat of old frame -- queue ack for
  431.              * expected frame
  432.              */
  433.             start_timer(&cb->tack);
  434.         else {            /* really bogus -- a NAKable frame */
  435.             rhdr.opcode = NR4OPACK | NR4NAK;
  436.             rhdr.yourindex = cb->yournum;
  437.             rhdr.yourid = cb->yourid;
  438.             rhdr.u.ack.rxseq = cb->rxpected;
  439.             nr4sframe(cb->remote.node,&rhdr,NULLBUF);
  440.         
  441.             /* Now make sure we don't send any more of these until
  442.              * we see some good data.  Otherwise full window
  443.              * retransmissions would result in a flurry of NAKs
  444.              */
  445.         
  446.             cb->naksent = 1;
  447.         }
  448.     }
  449.             
  450.     /* If this is a new frame, within the window, buffer it,
  451.      * then see what we can deliver
  452.      */
  453.     if(nr4between(cb->rxpected,rxseq,cb->rxpastwin)
  454.         && !cb->rxbufs[rxbuf].occupied){
  455. #ifdef NR4DEBUG
  456.         tprintf("Frame within window\n");
  457. #endif
  458.         cb->rxbufs[rxbuf].occupied = 1;
  459.         cb->rxbufs[rxbuf].data = bp;
  460.                 
  461.         for(rxbuf = cb->rxpected % window; cb->rxbufs[rxbuf].occupied;
  462.              rxbuf = cb->rxpected % window){
  463. #ifdef NR4DEBUG
  464.             tprintf("Removing frame from buffer %d\n", rxbuf);
  465. #endif
  466.             newdata = 1;
  467.             cb->rxbufs[rxbuf].occupied = 0;
  468.             append(&cb->rxq,cb->rxbufs[rxbuf].data);
  469.             cb->rxbufs[rxbuf].data = NULLBUF;
  470.             cb->rxpected = (cb->rxpected + 1) & NR4SEQMASK;
  471.             cb->rxpastwin = (cb->rxpastwin + 1) & NR4SEQMASK;
  472.         }
  473.         if(newdata){
  474.             cb->naksent = 0;    /* OK to send NAKs again */
  475.             if(cb->r_upcall != 0)
  476.                 (*cb->r_upcall)(cb,len_p(cb->rxq));
  477.  
  478.             /* Now that our upcall has had a shot at the queue, */
  479.             /* see if it's past the queue length limit.  If so, */
  480.             /* go into choked mode (i.e. flow controlled). */
  481.  
  482.             if(len_p(cb->rxq) > Nr4qlimit){
  483.                 cb->qfull = 1;
  484.                 nr4ackit((void *)cb);    /* Tell `em right away */
  485.             } else
  486.                 start_timer(&cb->tack);
  487.         }
  488.     } else     /* It's out of the window or we've seen it already */
  489.         free_p(bp);
  490. }
  491.  
  492.  
  493. /* Send the transmit buffer whose sequence number is seq */
  494. void
  495. nr4sbuf(cb, seq)
  496. struct nr4cb *cb;
  497. unsigned seq;
  498. {
  499.     struct nr4hdr hdr;
  500.     struct mbuf *bufbp, *bp;
  501.     unsigned bufnum = seq % cb->window;
  502.     struct timer *t;
  503.     
  504.     /* sanity check */
  505.     if(bufnum >= cb->window){
  506. #ifdef NRDEBUG
  507.         tprintf("sbuf: buffer number %u beyond window\n",bufnum);
  508. #endif
  509.         return;
  510.     }
  511.  
  512.     /* Stop the ACK timer, since our sending of the frame is
  513.      * an implied ACK.
  514.      */
  515.     stop_timer(&cb->tack);
  516.     
  517.     /* Duplicate the mbuf, since we have to keep it around
  518.      * until it is acknowledged
  519.      */
  520.     bufbp = cb->txbufs[bufnum].data;
  521.  
  522.     /* Notice that we use copy_p instead of dup_p.  This is because
  523.      * a frame can still be sitting on the AX.25 send queue when it
  524.      * get acknowledged, and we don't want to deallocate its data
  525.      * before it gets sent!
  526.      */
  527.     if((bp = copy_p(bufbp, len_p(bufbp))) == NULLBUF){
  528.         free_mbuf(bp);
  529.         return;
  530.     }
  531.  
  532.     /* Prepare the header */
  533.     if(cb->qfull)                /* are we choked? */
  534.         hdr.opcode = NR4OPINFO | NR4CHOKE;
  535.     else
  536.         hdr.opcode = NR4OPINFO;
  537.     hdr.yourindex = cb->yournum;
  538.     hdr.yourid = cb->yourid;
  539.     hdr.u.info.txseq = (unsigned char)(seq & NR4SEQMASK);
  540.     hdr.u.info.rxseq = cb->rxpected;
  541.     
  542.     /* Send the frame, then set and start the timer */
  543.     nr4sframe(cb->remote.node, &hdr, bp);
  544.  
  545.     t = &cb->txbufs[bufnum].tretry;
  546.     set_timer(t, (1 << cb->blevel) * (4 * cb->mdev + cb->srtt));
  547.     start_timer(t);
  548. }
  549.  
  550. /* Check to see if any of our frames have been ACKed */
  551.  
  552. static void
  553. nr4ackours(cb, seq, gotchoke)
  554. struct nr4cb *cb;
  555. unsigned seq;
  556. int gotchoke;    /* The choke flag is set in the received frame */
  557. {
  558.     unsigned txbuf;
  559.     struct timer *t;
  560.     
  561.     /* If we are choked, there is nothing in the send window
  562.      * by definition, so we can just return.
  563.      */
  564.     if(cb->choked)
  565.         return;
  566.         
  567.     /* Adjust seq to point to the frame being ACK'd, not the one
  568.      * beyond it, which is how it arrives.
  569.      */
  570.     seq = (seq - 1) & NR4SEQMASK;
  571.  
  572.     /* Free up all the ack'd frames, and adjust the round trip
  573.      * timing stuff
  574.      */
  575.     while (nr4between(cb->ackxpected, seq, cb->nextosend)){
  576. #ifdef NR4DEBUG
  577.         tprintf("Sequence # %u acknowledged\n", seq);
  578. #endif
  579.         cb->nbuffered--;
  580.         txbuf = cb->ackxpected % cb->window;
  581.         free_mbuf(cb->txbufs[txbuf].data);
  582.         cb->txbufs[txbuf].data = NULLBUF;
  583.         cb->ackxpected = (cb->ackxpected + 1) & NR4SEQMASK;
  584.  
  585.         /* Round trip time estimation, cribbed from TCP */
  586.         if(cb->txbufs[txbuf].retries == 0){
  587.             /* We only sent this one once */
  588.             int32 rtt;
  589.             int32 abserr;
  590.  
  591.             t = &cb->txbufs[txbuf].tretry;
  592.             /* get our rtt in msec */
  593.             rtt = dur_timer(t) - read_timer(t);
  594.             abserr = (rtt > cb->srtt) ? rtt - cb->srtt : cb->srtt - rtt;
  595.             cb->srtt = (cb->srtt * 7 + rtt) >> 3;
  596.             cb->mdev = (cb->mdev * 3 + abserr) >> 2;
  597.  
  598.             /* Reset the backoff level */
  599.             cb->blevel = 0;
  600.         }
  601.         stop_timer(&cb->txbufs[txbuf].tretry);
  602.     }    
  603.     /* Now we recalculate tmax, the maximum number of retries for
  604.      * any frame in the window.  tmax is used as a baseline to
  605.      * determine when the window has reached a new high in retries.
  606.      * We don't want to increment blevel for every frame that times
  607.      * out, since that would lead to us backing off too fast when
  608.      * all the frame timers expired at around the same time.
  609.      */
  610.     cb->txmax = 0;
  611.     
  612.     for(seq = cb->ackxpected;
  613.          nr4between(cb->ackxpected, seq, cb->nextosend);
  614.          seq = (seq + 1) & NR4SEQMASK)
  615.         if(cb->txbufs[seq % cb->window].retries > cb->txmax)
  616.             cb->txmax = cb->txbufs[seq % cb->window].retries;
  617.  
  618.     /* This is kind of a hack.  This function is called under
  619.      * three different conditions:  either we are choked, in
  620.      * which case we return immediately, or we are not choked,
  621.      * in which case we proceed normally to keep the send
  622.      * window full, or we have seen the choke flag for the first
  623.      * time.  In the last case, gotchoke is true while cb->choked
  624.      * is false.  We want to process any acknowledgments of existing
  625.      * frames in the send window before we purge it, while at the
  626.      * same time we don't want to take anything else off the txq
  627.      * or send it out.  So, in the third case we listed, we return
  628.      * now since we've processed the ACK.
  629.      */
  630.     
  631.     if(gotchoke)
  632.         return;
  633.         
  634.     nr4output(cb);            /* yank stuff off txq and send it */
  635.  
  636.     /* At this point, either the send window is full, or
  637.      * nr4output() didn't find enough on the txq to fill it.
  638.      * If the window is not full, then the txq must be empty,
  639.      * and we'll make a tx upcall
  640.      */
  641.     if(cb->nbuffered < cb->window && cb->t_upcall != 0)
  642.         (*cb->t_upcall)(cb, (int16)((cb->window - cb->nbuffered) * NR4MAXINFO));
  643.  
  644. }
  645.  
  646.  
  647. /* If the send window is open and there are frames on the txq,
  648.  * move as many as possible to the transmit buffers and send them.
  649.  * Return the number of frames sent.
  650.  */
  651. int
  652. nr4output(cb)
  653. struct nr4cb *cb;
  654. {
  655.     int numq, i;
  656.     struct mbuf *bp;
  657.     struct nr4txbuf *tp;
  658.  
  659.     /* Are we in the proper state? */
  660.     if(cb->state != NR4STCON || cb->choked)
  661.         return 0;        /* No sending if not connected */
  662.                     /* or if choked */
  663.         
  664.     /* See if the window is open */
  665.     if(cb->nbuffered >= cb->window)
  666.         return 0;
  667.  
  668.     numq = len_q(cb->txq);
  669.     
  670. #ifdef NR4DEBUG
  671.     tprintf("nr4output: %d packets on txq\n", numq);
  672. #endif
  673.     
  674.     for(i = 0; i < numq; i++){
  675.         bp = dequeue(&cb->txq);
  676. #ifdef NR4DEBUG
  677.         if(len_p(bp) > NR4MAXINFO){    /* should be checked higher up */
  678.             tprintf("Upper layers queued too big a buffer\n");
  679.             continue;
  680.         }
  681. #endif
  682.         /* Set up and send buffer */
  683.         tp = &cb->txbufs[cb->nextosend % cb->window];
  684.         tp->retries = 0;
  685.         tp->data = bp;
  686.         nr4sbuf(cb, cb->nextosend);
  687.  
  688.         /* Update window and buffered count */
  689.         cb->nextosend = (cb->nextosend + 1) & NR4SEQMASK;
  690.         if(++cb->nbuffered >= cb->window)
  691.             break;
  692.     }
  693.     return i;        
  694. }
  695.  
  696. void
  697. nr4state(cb, newstate)
  698. struct nr4cb *cb;
  699. int newstate;
  700. {
  701.     int i;
  702.     int oldstate = cb->state;
  703.     
  704.     cb->state = newstate;
  705.  
  706.     switch(cb->state){
  707. #ifdef NR4TDISC
  708.     case NR4STCON:
  709.         /* We're connected now, start inactivity timer - WG7J */
  710.         set_timer(&cb->tdisc,Nr4tdiscinit*1000L);
  711.         /*
  712.             cb->tdisc.func = nr4_redundant ;
  713.          * Second try; the call to nr4_redundant() (see above)
  714.          * doesn't seem to catch ALL situations.
  715.          * Changes are if we reachs this, with 'normal' values of tdisc,
  716.          * the other end has already timed out and retried out.
  717.          * So simply reset the control block - WG7J
  718.          */
  719.         cb->tdisc.func = reset_nr4;
  720.         cb->tdisc.arg = cb ;
  721.         start_timer(&cb->tdisc) ;
  722.         break;
  723. #endif
  724.     case NR4STDPEND:
  725.         stop_timer(&cb->tchoke);
  726. #ifdef NR4TDISC
  727.         start_timer(&cb->tdisc);
  728. #endif
  729.  
  730.         /* When we request a disconnect, we lose the contents of
  731.          * our transmit queue and buffers, but we retain our ability
  732.          * to receive any packets in transit until a disconnect
  733.          * acknowledge arrives
  734.          */
  735.         free_q(&cb->txq);
  736.         
  737.         for(i = 0; i < cb->window; i++){
  738.             free_mbuf(cb->txbufs[i].data);
  739.             cb->txbufs[i].data = NULLBUF;
  740.             stop_timer(&cb->txbufs[i].tretry);
  741.         }
  742.         
  743.         /* Tidy up stats: roll the top window pointer back
  744.          * and reset nbuffered to reflect this.  Not really
  745.          * necessary, but leads to a bit more truth telling
  746.          * in the status displays.
  747.          */
  748.         cb->nextosend = cb->ackxpected;
  749.         cb->nbuffered = 0;
  750.         break;
  751.       case NR4STDISC:
  752.         stop_timer(&cb->tchoke);
  753.         stop_timer(&cb->tack);
  754.         stop_timer(&cb->tcd);
  755. #ifdef NR4TDISC
  756.         stop_timer(&cb->tdisc);
  757. #endif
  758.  
  759.         /* We don't clear the rxq, since the state change upcall
  760.          * may pull something off of it at the last minute.
  761.          */
  762.         free_q(&cb->txq);
  763.  
  764.         /* The following loop will only be executed if the
  765.          * window was set, since when the control block is
  766.          * calloc'd the window field gets a 0 in it.  This
  767.          * protects us from dereferencing an unallocated
  768.          * window buffer pointer
  769.          */
  770.         for(i = 0; i < cb->window; i++){
  771.             free_mbuf(cb->rxbufs[i].data);
  772.             cb->rxbufs[i].data = NULLBUF;
  773.             free_mbuf(cb->txbufs[i].data);
  774.             cb->txbufs[i].data = NULLBUF;
  775.             stop_timer(&cb->txbufs[i].tretry);
  776.         }
  777.         break;
  778.     }
  779.  
  780.     if(oldstate != newstate && cb->s_upcall != NULLVFP)
  781.         (*cb->s_upcall)(cb, oldstate, newstate);
  782.  
  783.     /* We take responsibility for deleting the circuit
  784.      * descriptor.  Don't do this anywhere else!
  785.      */
  786.     if(newstate == NR4STDISC)
  787.         free_n4circ(cb);
  788. }
  789.  
  790. /* Process NAKs.  seq indicates the next frame expected by the
  791.  * NAK'ing station.
  792.  */
  793.  
  794. static void
  795. nr4gotnak(cb, seq)
  796. struct nr4cb *cb;
  797. unsigned seq;
  798. {
  799.     if(nr4between(cb->ackxpected, seq, cb->nextosend))
  800.         nr4sbuf(cb, seq);
  801. }
  802.  
  803.  
  804. /* This is called when we first get a CHOKE indication from the
  805.  * remote.  It purges the send window and sets the choke timer.
  806.  */
  807.  
  808. static void
  809. nr4choke(cb)
  810. struct nr4cb *cb;
  811. {
  812.     unsigned seq;
  813.     struct mbuf *q, *bp;
  814.     struct nr4txbuf *t;
  815.  
  816.     q = cb->txq;
  817.  
  818.     /* We purge the send window, returning the buffers to the
  819.      * txq in the proper order.
  820.      */
  821.     for(seq = (cb->nextosend - 1) & NR4SEQMASK;
  822.          nr4between(cb->ackxpected, seq, cb->nextosend);
  823.          seq = (seq - 1) & NR4SEQMASK){
  824.  
  825.         t = &cb->txbufs[seq % cb->window];
  826.         stop_timer(&t->tretry);
  827.         bp = t->data;
  828.         t->data = NULLBUF;
  829.         enqueue(&bp, q);    /* prepend this packet to the queue */
  830.         q = bp;
  831.      }
  832.  
  833.     cb->nextosend = cb->ackxpected;    /* close the window */
  834.     cb->nbuffered = 0;        /* nothing in the window */
  835.     cb->txq = q;            /* Replace the txq with the one that has */
  836.                     /* the purged packets prepended */
  837.     cb->choked = 1;        /* Set the choked flag */
  838.  
  839.     start_timer(&cb->tchoke);
  840. }
  841.